#include "defines.h"
#include "system.h"
#include "display.h"
#include "image.h"
#include "wdt.h"
#include "led.h"

#define IMG_BYTES_PER_ROW   24
#define HVC_RISE_TIME       3000ul     // Measure 1.7 ms to 28V w/ Vin = 2.4V.
#define HVC_DISCHARGE_TIME  1100000ul  // Measure 1.1 s decay from 28V to 0.1V.
//#define A2D_AT_10C          2300       // Temperature A/D reading at 10C.
#define MIN_RELAX_TIME      60000ul    // 60 ms
#define LCD_ROW 			100

void Update2(void)
{   
	Clearn();
//	Display( BitmapDot, 0, 0, 
//		30000ul, 2000ul, 4, 60000ul, 7500ul, 2, 0 ,1, 101);      
	//	Display(nBitmapDot, 0, 0, 
	//	30000ul, 2000ul, 4, 60000ul, 7500ul, 2, 0 ,1, 101);   
}


void Clearn()
{
	// Enable VCC to drivers (if not permanently powered).
	clr_nEN_3V();
	
	// Enable power to boost converter and turn on.
	clr_nEN_VDD();
	set_EN_HV();
	
	// Configure HVC to planar erase/drive voltage.
	set_PL_EN();
	//Tick_WDT();
	// Give boost converter time to charge.
	SetTimer(HVC_RISE_TIME);
	WaitTimer();
	//Tick_WDT();
	// Initialize segment driver input logic.
	set_LATCH();
	clr_LATCH();
	set_LATCH();
	clr_LATCH();
	
	
    // Erase the display to all bright.
    Erase(0, 11250ul, 21650ul, 2 /* NumErase */);   //1125 
	//Tick_WDT();
    // Configure HVC to focal conic reset voltage.
    clr_PL_EN();
	
    // Delay between planar and fc erase.
    //Tick_WDT();

    SetTimer(60000ul);
    WaitTimer();
	
	//Tick_WDT();
    // Erase the display to all dark.
    Erase(0, 11250ul, 21650ul,2);
	//Tick_WDT();
    // Configure HVC to planar erase/drive voltage.
    set_PL_EN();
	
    // Delay between erase and drive scan.
//	SetTimer(ScanPW);
//    WaitTimer();
	
    // Drive the image data.
	
	
	// Turn off HVC voltage selection FET.
	clr_PL_EN();
	
	// Disable and power down boost converter.
	clr_EN_HV();
	set_nEN_VDD();
	
	// Give high voltage time to discharge before powering off driver logic
	// (not required if VCC permanently supplied to drivers).
	//Tick_WDT();
    LED1_set();
	SetTimer(HVC_DISCHARGE_TIME);
	WaitTimer();
    LED1_reset();
	//Tick_WDT();
	// Power down VCC to drivers (if not permanently powered).
	set_nEN_3V();
}


///////////////////////////////////////////////////////////////////////////////
// Function: Display
// Purpose:  Updates the display with the provided parameters.
// Inputs:   pImage    - pointer to the image data
//           Border    - (0) dark image border, (else) bright image border
//           Frame     - (0, else) polarity of the present frame
//           ErasePW   - duration (us) of each pos. or neg erase pulse 
//           Stir      - duration (us) of the off period between erase pulses 
//           NumErase  - number of FC erase pulses (counts both pos. and neg.)
//           Relax     - duration (us) between planar and focal conic erases
//           ScanPW    - duration (us) of each pos. or neg. scan pulse
//           NumScan   - number of scan pulses (counts both pos. and neg.)
//           ElecErase - (0) regular image update, (else) electronic erase
// Outputs:  None.
// Notes:    Planar erase pulses are hardwired to two.
///////////////////////////////////////////////////////////////////////////////
void Display_fan(const unsigned char pImage[][24], unsigned char Border, unsigned char Frame, 
             unsigned long ErasePW, unsigned long Stir, unsigned char NumErase, unsigned long Relax, 
             unsigned long ScanPW, unsigned char NumScan, unsigned char ElecErase,unsigned char y1, unsigned char y2)
{
	// Enable VCC to drivers (if not permanently powered).
	clr_nEN_3V();
	
	// Enable power to boost converter and turn on.
	clr_nEN_VDD();
	set_EN_HV();
	
	// Configure HVC to planar erase/drive voltage.
	set_PL_EN();
	//Tick_WDT();
	// Give boost converter time to charge.
	SetTimer(HVC_RISE_TIME);
	WaitTimer();
	
	// Initialize segment driver input logic.
	set_LATCH();
	clr_LATCH();
	set_LATCH();
	clr_LATCH();
	//Tick_WDT();
	if (ElecErase) // Perform electronic erase?
	{
		//  Perform the electronic erase (a single, long unipolar pulse).
		Erase(Frame, ErasePW, 0 /* Stir */, 1 /* NumPulses */);
	}
	else  // Regular image update.
	{
		// Erase the display to all bright.
		// Erase(Frame, ErasePW, Stir, 2 /* NumErase */);
		
		// Configure HVC to focal conic reset voltage.
		clr_PL_EN();
		
		// Delay between planar and fc erase.
		//Tick_WDT();
		SetTimer(Relax);
		WaitTimer();
		
		// Erase the display to all dark.
		//   Erase(Frame, ErasePW, Stir, NumErase);
		
		// Configure HVC to planar erase/drive voltage.
		set_PL_EN();
		
		// Delay between erase and drive scan.
		//Tick_WDT();
		SetTimer(ScanPW);
		WaitTimer();
		//Tick_WDT();
		// Drive the image data.
		Scan_fan(pImage, Border, ScanPW, NumScan, y1, y2);
	}
	
	// Turn off HVC voltage selection FET.
	clr_PL_EN();
	
	// Disable and power down boost converter.
	clr_EN_HV();
	set_nEN_VDD();
	//Tick_WDT();
	// Give high voltage time to discharge before powering off driver logic
	// (not required if VCC permanently supplied to drivers).
	SetTimer(HVC_DISCHARGE_TIME);
	WaitTimer();
	//Tick_WDT();
	// Power down VCC to drivers (if not permanently powered).
	set_nEN_3V();
}

void Display(const unsigned char pImage[][24], unsigned char Border, unsigned char Frame, 
             unsigned long ErasePW, unsigned long Stir, unsigned char NumErase, unsigned long Relax, 
             unsigned long ScanPW, unsigned char NumScan, unsigned char ElecErase,unsigned char y1, unsigned char y2)
{
	// Enable VCC to drivers (if not permanently powered).
	clr_nEN_3V();
	
	// Enable power to boost converter and turn on.
	clr_nEN_VDD();
	set_EN_HV();
	
	// Configure HVC to planar erase/drive voltage.
	set_PL_EN();
	//Tick_WDT();
	// Give boost converter time to charge.
	SetTimer(HVC_RISE_TIME);
	WaitTimer();
	
	// Initialize segment driver input logic.
	set_LATCH();
	clr_LATCH();
	set_LATCH();
	clr_LATCH();
	
	if (ElecErase) // Perform electronic erase?
	{
		//  Perform the electronic erase (a single, long unipolar pulse).
		Erase(Frame, ErasePW, 0 /* Stir */, 1 /* NumPulses */);
	}
	else  // Regular image update.
	{
		// Erase the display to all bright.
		// Erase(Frame, ErasePW, Stir, 2 /* NumErase */);
		
		// Configure HVC to focal conic reset voltage.
		clr_PL_EN();
		
		// Delay between planar and fc erase.
		//Tick_WDT();
		SetTimer(Relax);
		WaitTimer();
		
		// Erase the display to all dark.
		//   Erase(Frame, ErasePW, Stir, NumErase);
		
		// Configure HVC to planar erase/drive voltage.
		set_PL_EN();
		
		// Delay between erase and drive scan.
		//Tick_WDT();
		SetTimer(ScanPW);
		WaitTimer();
		
		// Drive the image data.
		Scan(pImage, Border, ScanPW, NumScan, y1, y2);
	}
	
	// Turn off HVC voltage selection FET.
	clr_PL_EN();
	
	// Disable and power down boost converter.
	clr_EN_HV();
	set_nEN_VDD();
	
	// Give high voltage time to discharge before powering off driver logic
	// (not required if VCC permanently supplied to drivers).
	//Tick_WDT();
	SetTimer(HVC_DISCHARGE_TIME);
	WaitTimer();
	
	// Power down VCC to drivers (if not permanently powered).
	set_nEN_3V();
}


///////////////////////////////////////////////////////////////////////////////
// Function: Erase
// Purpose:  Erases display to the bright state with the provided parameters.
// Inputs:   Frame     - polarity of the present frame
//           ErasePW   - duration (us) of each pos. or neg. erase pulse
//           Stir      - duration (us) of the off period between erase pulses 
//           NumPulses - number of erase pulses (counts both pos. and neg.)
// Outputs:  None.
// Notes:    None.
///////////////////////////////////////////////////////////////////////////////
void Erase(unsigned char Frame, unsigned long ErasePW, unsigned long Stir, unsigned char NumPulses)
{
	unsigned char i, j;
	
	// Initialize phase signal.
	if (Frame)
		set_PHASE();
	else
		clr_PHASE();
	
	// Loop through the erase pulses.
	for (i = 0; i < NumPulses; i++)
	{
		// Turn on driver outputs.
		set_ENABLE();
		
		// Clock erase data and latch to driver outputs.
		ClockFixedData(0xff);
		set_LATCH();
		clr_LATCH();
		
		// Select rows for erase pulse.
		for (j = 0; j < LCD_ROW; j++)
		{
			set_RCLK();
			clr_RCLK();
		}
		
		// Hold erase pulse.
		//Tick_WDT();
		SetTimer(ErasePW);
		WaitTimer();
		
		// Terminate erase pulse.
		clr_ENABLE();
		
		// Invert phase for next pulse.
		tgl_PHASE();
		
		// Delay for the stir.
		if (i != (NumPulses - 1))
		{
			//Tick_WDT();
			SetTimer(Stir);
			WaitTimer();
		}
	}
}

void ClockImageData_fan(const unsigned char *pData, unsigned char Border)
{
	int i;
	unsigned char Data, SrcMask, DstMask; 
	for (i = 11; i >= 0; i--)
	{
		Data = 0x00;
		DstMask = 0x01;
    
		// Loop through each bit in the byte of source data.
		for (SrcMask = 0x80; SrcMask != 0; SrcMask = SrcMask >> 1)
		{
		// Set the output data bit if the corresponding image data bit is set.
			if (SrcMask & pData[i])
				Data |= DstMask;
      
			// Update the ouput data bit mask.  
			DstMask = DstMask << 1;
		}

		set_DATA(~Data);
		set_CCLK();
		clr_CCLK();	
	}

    for (i = 12; i < 24; i++)
	{	
		if(i == 12)
		{
			set_DATA(~(pData[i]>>1));
			set_CCLK();
			clr_CCLK();	
		}
		else
		{
			set_DATA(~((pData[i]>>1)|(pData[i-1]<<7))); 
			set_CCLK();
			clr_CCLK();	
		}  
	}
}


void ClockImageData(const unsigned char *pData, unsigned char Border)
{
	int i;
	unsigned char Data, SrcMask, DstMask; 
	for (i = 11; i >= 0; i--)
	{
		Data = 0x00;
		DstMask = 0x01;
    
		// Loop through each bit in the byte of source data.
		for (SrcMask = 0x80; SrcMask != 0; SrcMask = SrcMask >> 1)
		{
		// Set the output data bit if the corresponding image data bit is set.
			if (SrcMask & pData[i])
				Data |= DstMask;
      
			// Update the ouput data bit mask.  
			DstMask = DstMask << 1;
		}

//		set_DATA(~Data);
		set_DATA(Data); 
		set_CCLK();
		clr_CCLK();	
	}

    for (i = 12; i < 24; i++)
	{	
		if(i == 12)
		{
//			set_DATA(~(pData[i]>>1));
			set_DATA(pData[i]>>1); 
			set_CCLK();
			clr_CCLK();	
		}
		else
		{
			set_DATA((pData[i]>>1)|(pData[i-1]<<7)); 
//			set_DATA(~((pData[i]>>1)|(pData[i-1]<<7))); 
			set_CCLK();
			clr_CCLK();	
		}  
	}
}

void Scan(const unsigned char pImage[][24], unsigned char Border, unsigned long ScanPW, unsigned char NumPulses ,unsigned char y1, unsigned char y2)
{
	unsigned char row, pulse;
	
	// Loop through all rows:
	//   (1) dummy + (1) top border + (72) image + (1) bottom border + (5) dummy
	for (row = 0; row < y2; row++)
	{
        
		// Load segment data for next row to drive.
		if ( (row == 0) || (row ==100) )  // Top or bottom border?
    //    if ( (row == 1) || (row == 102) )  // Top or bottom border?  ///*** (row == 74) )
		{
			if (Border == 0)  // Dark border?
				ClockFixedData(0x00);
			else              // Bright border.
				ClockFixedData(0xff);
		}
		
		set_nEN_VDD();
		
		if ( row >= y1)  // Image row.
		{
			clr_nEN_VDD();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();   
			_NOP();
			_NOP();
			ClockImageData(pImage[row], Border);
		}
		
		// Prepare to latch the new segment data to the driver outputs.
		set_LATCH();
		
		// Loop through all drive pulses for the current row. 
		for (pulse = 0; pulse < NumPulses; pulse++)
		{
			if (pulse == 0)  // Starting a new row?
			{
				if (row == 0)  // Is the new row the 1st row?
				{
					// Initialize dummy row at top of display.
					set_ENABLE();         // Turn on drivers.
					clr_LATCH();          // Prep. latch for clocking next set of data.
					//Tick_WDT();
					SetTimer(ScanPW);     // Start timing initial drive pulse.
				}
				else  // (pulse == 0), (row != 0)
				{
					if (row == 1)
						set_DATA(0xff);       // Prepare data to select top border row.
					else
						set_DATA(0x00);       // Prepare data to advance select row.
					
					set_RCLK();             // Prepare row clock.
					
					// Typically the PHASE signal toggles for every new pulse, including
					// the 1st pulse of a new row.  However, when using the low power
					// waveform with NumPulses equal to one, the PHASE is kept constant
					// over the entire scan.
					if (NumPulses == 1)
					{
						WaitTimer();        // Wait for end of previous row drive pulse.
						clr_LATCH_RCLK();   // Start new row drive pulse (no PHASE toggle).
						//Tick_WDT();
						SetTimer(ScanPW);   // Start timing drive pulse of new row.
					}
					else  
					{
						WaitTimer();        // Wait for end of last pulse of prev. row.
						tgl_LATCH_RCLK_PHASE(); // Start 1st drive pulse of new row.
						//Tick_WDT();
						SetTimer(ScanPW);   // Start timing 1st drive pulse of new row.
					}
				} 
			}      
			else // pulse != 0
			{
				// Subsequent pulses in the row need only a PHASE toggle. 
				WaitTimer();       // Wait for end of previous pulse.
				tgl_PHASE();       // Initialize new pulse by toggling phase.
				//Tick_WDT();
				SetTimer(ScanPW);  // Start timing new pulse.
			}
		} // for (pulse = 0; pulse < NumPulses; pulse++)
	} // for (row = 0; row < 74; row++)
	
	WaitTimer();    // Wait for end of final drive pulse.
	clr_ENABLE();   // Turn off driver outputs.
	clr_PHASE();    // Ensure phase is low in case driver is to be powered off.
}


void Scan_fan(const unsigned char pImage[][24], unsigned char Border, unsigned long ScanPW, unsigned char NumPulses ,unsigned char y1, unsigned char y2)
{
	unsigned char row, pulse;
	
	// Loop through all rows:
	//   (1) dummy + (1) top border + (72) image + (1) bottom border + (5) dummy
	for (row = 0; row < y2; row++)
	{
        
		// Load segment data for next row to drive.
		if ( (row == 0) || (row ==100) )  // Top or bottom border?
    //    if ( (row == 1) || (row == 102) )  // Top or bottom border?  ///*** (row == 74) )
		{
			if (Border == 0)  // Dark border?
				ClockFixedData(0x00);
			else              // Bright border.
				ClockFixedData(0xff);
		}
		
		set_nEN_VDD();
		
		if ( row >= 26)  // Image row.
		{
			clr_nEN_VDD();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();   
			_NOP();
			_NOP();
			ClockImageData_fan(pImage[row], Border);
		} else {
			clr_nEN_VDD();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();
			_NOP();   
			_NOP();
			_NOP();
			ClockImageData(pImage[row], Border);
		}
		
		// Prepare to latch the new segment data to the driver outputs.
		set_LATCH();
		
		// Loop through all drive pulses for the current row. 
		for (pulse = 0; pulse < NumPulses; pulse++)
		{
			if (pulse == 0)  // Starting a new row?
			{
				if (row == 0)  // Is the new row the 1st row?
				{
					// Initialize dummy row at top of display.
					set_ENABLE();         // Turn on drivers.
					clr_LATCH();          // Prep. latch for clocking next set of data.
					//Tick_WDT();
					SetTimer(ScanPW);     // Start timing initial drive pulse.
				}
				else  // (pulse == 0), (row != 0)
				{
					if (row == 1)
						set_DATA(0xff);       // Prepare data to select top border row.
					else
						set_DATA(0x00);       // Prepare data to advance select row.
					
					set_RCLK();             // Prepare row clock.
					
					// Typically the PHASE signal toggles for every new pulse, including
					// the 1st pulse of a new row.  However, when using the low power
					// waveform with NumPulses equal to one, the PHASE is kept constant
					// over the entire scan.
					if (NumPulses == 1)
					{
						WaitTimer();        // Wait for end of previous row drive pulse.
						clr_LATCH_RCLK();   // Start new row drive pulse (no PHASE toggle).
						SetTimer(ScanPW);   // Start timing drive pulse of new row.
					}
					else  
					{
						WaitTimer();        // Wait for end of last pulse of prev. row.
						tgl_LATCH_RCLK_PHASE(); // Start 1st drive pulse of new row.
						//Tick_WDT();
						SetTimer(ScanPW);   // Start timing 1st drive pulse of new row.
					}
				} 
			}      
			else // pulse != 0
			{
				// Subsequent pulses in the row need only a PHASE toggle. 
				WaitTimer();       // Wait for end of previous pulse.
				tgl_PHASE();       // Initialize new pulse by toggling phase.
				//Tick_WDT();
				SetTimer(ScanPW);  // Start timing new pulse.
			}
		} // for (pulse = 0; pulse < NumPulses; pulse++)
	} // for (row = 0; row < 74; row++)
	
	WaitTimer();    // Wait for end of final drive pulse.
	clr_ENABLE();   // Turn off driver outputs.
	clr_PHASE();    // Ensure phase is low in case driver is to be powered off.
}

void ClockFixedData(unsigned char Data)
{
	unsigned char i;
	
	// Output the data value to the segment driver.
	
	
	// Clock the segment driver full.  
	
	
	for (i = 0; i < IMG_BYTES_PER_ROW; i++)
	{
		set_DATA(Data);
		set_CCLK();
		clr_CCLK();
	}
	
}
